﻿#include "ZTextEdit.h"
#include "ZScrollBar.h"
#include "ZPaintManager.h"
#include "ZControlFactory.h"
#include "ZWindow.h"
#include "libunibreak/linebreak.h"
#include "libunibreak/wordbreak.h"

namespace ZuiLib
{

#define CARET_OFFSET_Y 8

ZTextEdit::ZTextEdit()	
	:m_dwTextColor(0), m_dwDisabledTextColor(0), m_nFontSize(_dpi_scale(DEFAULT_FONT_SIZE))
{
	m_linePadding=_dpi_scale(6);
	m_bMouseEnabled=true;
	m_readOnly=false;
	m_needUpdateCaret=true;
	m_needScrollToCaret=false;
	m_uState=0;

	m_editingBegin=0;
	m_editingEnd=0;
	m_editingOffset=0;

	SetRectEmpty(&m_rcTextPadding);
	m_caret=new ZRefCountedObject<ZCaret>(this);

	m_currentWidth = -1;
}


ZTextEdit::~ZTextEdit()
{

}

const char* ZTextEdit::GetClass() const
{
	return "TextEdit";
}


void* ZTextEdit::GetInterface(const char* pstrName)
{
	if( strcmp(pstrName,"TextEdit") == 0 ) return static_cast<ZTextEdit*>(this);
    return ZContainer::GetInterface(pstrName);
}


ZFreeTypeFontPtr ZTextEdit::GetFont()
{
	return GetRenerder()->FindFont(m_sFont, m_nFontSize);
}

ZString ZTextEdit::GetText() const
{
	return m_doc.GetText();
}


void ZTextEdit::SetText(const char* buf)
{
	m_doc.SetText(buf);
	NeedUpdate();
}

void ZTextEdit::AppendText(const char* pstrText)
{
	ZWString utf16;
	ZString textUtf8 = pstrText;
	Utf8ToUtf16(&textUtf8, &utf16);
	m_doc.Insert(m_doc.GetLength(), 
		utf16.GetString(), utf16.GetLength());
	NeedUpdate();
}


void ZTextEdit::SetTextColor(color_t dwTextColor)
{
	m_dwTextColor = dwTextColor;
	m_caret->SetColor(m_dwTextColor);
	Invalidate();
}


color_t ZTextEdit::GetTextColor() const
{
	return m_dwTextColor;
}
void ZTextEdit::SetDisabledTextColor(color_t dwTextColor)
{
	m_dwDisabledTextColor = dwTextColor;
}
color_t ZTextEdit::GetDisabledTextColor() const
{
	return m_dwDisabledTextColor;
}
void ZTextEdit::SetFontName(const char* font)
{
	m_sFont=font;
}

const char* ZTextEdit::GetFontName()
{
	return m_sFont;
}
RECT ZTextEdit::GetTextPadding() const
{
	return m_rcTextPadding;
}
void ZTextEdit::SetTextPadding(RECT rc)
{
	m_rcTextPadding=rc;
}


void ZTextEdit::DoEvent(TEventUI& event)
{
	switch(event.Type)
	{
	case UIEVENT_SETFOCUS:
		{
			RECT rcCaret=GetCaretRect();
			m_caret->SetPos(rcCaret);
			m_caret->ShowCaret(true);

			if (!m_readOnly)
			{
				ZRect rc(rcCaret);
				rc.y += _dpi_scale(CARET_OFFSET_Y);
				SDL_StartTextInput();

				ZScale scale = GetWindow()->GetRenderScale();
				rc.x = rc.x * scale.den / scale.num;
				rc.y = rc.y * scale.den / scale.num;
				rc.w = rc.w * scale.den / scale.num;
				rc.h = rc.h * scale.den / scale.num;
				SDL_SetTextInputRect(&rc);
			}
		}
		break;
	case UIEVENT_KILLWINDOWFOCUS:
		if (m_pManager)
			m_pManager->SetFocus(NULL);
	case UIEVENT_KILLFOCUS:
		m_caret->ShowCaret(false);
		if (!m_readOnly)
			SDL_StopTextInput();
		break;
	case UIEVENT_BUTTONDOWN:
		{
			SetCaretPos(event.ptMouse);
			m_selBegin=m_caretPos;
			m_selEnd=m_caretPos;

			m_editingBegin=m_caretPos;
			m_editingEnd=m_caretPos;
			m_editingOffset=0;

			m_uState|=UISTATE_PUSHED;
			Invalidate();
		}
		break;

	case UIEVENT_BUTTONUP:
		{
			m_uState &= ~UISTATE_PUSHED;
			Invalidate();
		}
		break;

	case UIEVENT_MOUSEMOVE:
		{
			if ((m_uState & UISTATE_PUSHED)!=0)
			{
				if (event.ptMouse.y < GetPos().top - m_rcTextPadding.top)
				{
					LineUp();
				}
				else if (event.ptMouse.y > GetPos().bottom + m_rcTextPadding.bottom)
				{
					LineDown();
				}

				m_selEnd=CharFromPos(event.ptMouse);
				Invalidate();
			}
		}
		break;

	case UIEVENT_MOUSEENTER:
		{
			if( IsEnabled() ) {
				m_uState |= UISTATE_HOT;
				GetWindow()->SetCursor(SDL_SYSTEM_CURSOR_IBEAM);
				Invalidate();
			}
			break;
		}
	case UIEVENT_MOUSELEAVE:
		{
			if( IsEnabled() ) {
				m_uState &= ~UISTATE_HOT;
				GetWindow()->SetCursor(SDL_SYSTEM_CURSOR_ARROW);
				Invalidate();
			}
			break;
		}

	case UIEVENT_KEYDOWN:
		{
			SDL_Keysym* key=(SDL_Keysym*)event.wParam;
			switch (key->sym)
			{
			case SDLK_BACKSPACE:
				if (!m_readOnly && m_editingBegin == m_editingEnd)
				{
					if (m_selBegin == m_selEnd)
					{
						if (m_caretPos > 0)
							m_doc.Remove(--m_caretPos);
					}
					else
					{
						RemoveSel();
					}
					m_needScrollToCaret = true;
					NeedUpdate();
					SignalTextChanged(this);
				}
				break;
			case SDLK_DELETE:
				if (!m_readOnly && m_editingBegin == m_editingEnd)
				{
					if (m_selBegin == m_selEnd)
					{
						if (m_caretPos < m_doc.GetLength())
							m_doc.Remove(m_caretPos);
					}
					else
					{
						RemoveSel();
					}
					m_needScrollToCaret = true;
					NeedUpdate();
					SignalTextChanged(this);
				}
				break;
			case SDLK_LEFT:

				if (m_editingBegin == m_editingEnd)
				{
					if (m_caretPos>0)
					{
						--m_caretPos;
						ScrollToCaret();
					}
					else
					{
						m_selBegin = m_caretPos;
						m_selEnd = m_caretPos;
						Invalidate();
					}
				}
				break;
			case SDLK_RIGHT:
				if (m_caretPos<m_doc.GetLength())
				{
					++m_caretPos;
					int len= m_doc.GetLength();
					if (m_caretPos>len)
					{
						m_caretPos=len;
						m_needScrollToCaret=true;
					}
					m_selBegin=m_caretPos;
					m_selEnd=m_caretPos;
					ScrollToCaret();
				}
				else
				{
					m_selBegin=m_caretPos;
					m_selEnd=m_caretPos;
					Invalidate();
				}
				break;
			case SDLK_UP:
				{
					int nLine=LineFromChar(m_caretPos);

					if(nLine>0)
					{
						ZTextEditRow & foreRow=m_rows[nLine-1];
						ZTextEditRow & curRow=m_rows[nLine];

						int offset=m_caretPos-curRow.m_range.minPos;
						m_caretPos=foreRow.m_range.minPos+offset;
						if (m_caretPos>foreRow.m_range.maxPos)
							m_caretPos=foreRow.m_range.maxPos;
						ScrollToCaret();
					}
					m_selBegin=m_caretPos;
					m_selEnd=m_caretPos;
				}
				break;
			case SDLK_DOWN:
				{
					int nLine=LineFromChar(m_caretPos);

					if(nLine+1 <m_rows.size())
					{
						ZTextEditRow & nextRow=m_rows[nLine+1];
						ZTextEditRow & curRow=m_rows[nLine];

						int offset=m_caretPos-curRow.m_range.minPos;
						m_caretPos=nextRow.m_range.minPos+offset;
						if (m_caretPos>nextRow.m_range.maxPos)
							m_caretPos=nextRow.m_range.maxPos;
						ScrollToCaret();
					}
					m_selBegin=m_caretPos;
					m_selEnd=m_caretPos;
				}
				break;
			case SDLK_RETURN:
				if (!m_readOnly)
				{
					m_doc.Insert(m_caretPos,'\n');
					m_caretPos+=1;
					m_needScrollToCaret=true;
					NeedUpdate();
					SignalTextChanged(this);
				}
				break;

			case SDLK_c:
				{
					if (CheckKeyState(KS_CTRL))
					{
						Copy();
					}
				}
				break;

			case SDLK_x:
				if (!m_readOnly && CheckKeyState(KS_CTRL))
				{
					Cut();
				}
				break;

			case SDLK_v:
				if (!m_readOnly && CheckKeyState(KS_CTRL))
				{
					Paste();
				}
				break;
			case SDLK_a:
				if (CheckKeyState(KS_CTRL))
				{
					SelAll();
				}
				break;
			case SDLK_z:
				if (!m_readOnly && CheckKeyState(KS_CTRL))
				{
					Undo();
				}
				break;
			}
		}
		break;
	case UIEVENT_TEXTINPUT:
		if (!m_readOnly)
		{
			SDL_TextInputEvent* sdlEv=(SDL_TextInputEvent*)event.wParam;
			ZString utf8(sdlEv->text);
			ZWString utf16;
			Utf8ToUtf16(&utf8,&utf16);

			RemoveSel();//删除选中的字符
			RemoveEditing();

			m_doc.Insert(m_caretPos,utf16);
			m_caretPos+=utf16.GetLength();
			m_needScrollToCaret=true;
			NeedUpdate();

			SignalTextChanged(this);
		}
		break;
	case UIEVENT_TEXTEDITING:
		if (!m_readOnly)
		{
			SDL_TextEditingEvent* sdlEv=(SDL_TextEditingEvent*)event.wParam;
			ZString utf8(sdlEv->text);
			ZWString utf16;
			Utf8ToUtf16(&utf8,&utf16);

			RemoveSel();
			RemoveEditing();

			int len=utf16.GetLength();
			m_editingBegin=m_caretPos;
			m_editingEnd=m_editingBegin+len;

			m_editingOffset=ZMIN(sdlEv->start,len);

			m_doc.InsertEditing(m_caretPos,utf16);
			m_caretPos+=m_editingOffset;
			m_needScrollToCaret=true;
			NeedUpdate();
		}
		break;
	default:
		ZContainer::DoEvent(event);
	}
}

void ZTextEdit::SetReadOnly(bool readonly) {
	m_readOnly = readonly;
	m_doc.SetReadOnly(readonly);
}


void ZTextEdit::Copy()
{
	ZString textUtf8;
	if(m_selEnd != m_selBegin)
	{
		int selBegin=m_selBegin;
		int selEnd=m_selEnd;
		if(selBegin>selEnd)
		{
			selBegin=m_selEnd;
			selEnd=m_selBegin;
		}

		ZWString text= m_doc.GetRange(selBegin,selEnd);
		Utf16ToUtf8(&text,&textUtf8);
	}
	SDL_SetClipboardText(textUtf8.GetString());
}


void ZTextEdit::Cut()
{
	if(m_selEnd != m_selBegin)
	{
		int selBegin=m_selBegin;
		int selEnd=m_selEnd;
		if(selBegin>selEnd)
		{
			selBegin=m_selEnd;
			selEnd=m_selBegin;
		}

		ZString textUtf8;
		ZWString text= m_doc.GetRange(selBegin,selEnd);
		Utf16ToUtf8(&text,&textUtf8);

		SDL_SetClipboardText(textUtf8.GetString());


		RemoveSel();
		NeedUpdate();
		SignalTextChanged(this);
	}

}

void ZTextEdit::Undo() {
	int selBegin = m_doc.Undo();
	if (selBegin >= 0) {

		m_selEnd = selBegin;
		m_selBegin = selBegin;
		m_caretPos = selBegin;

		NeedUpdate();

		SignalTextChanged(this);
	}
}

void ZTextEdit::Paste()
{
	if (m_readOnly)
		return;

	if (!SDL_HasClipboardText())
		return;

	char* textUtf8=SDL_GetClipboardText();
	ZWString utf16(textUtf8);
	SDL_free(textUtf8);
	RemoveSel();
	
	ZWString temp;
	const ZWChar* str=utf16.GetString();

	while (*str)
	{
		if (*str!='\r')
		{
			temp.Append(*str);
		}
		++str;
	}

	m_doc.Insert(m_caretPos,temp);
	m_caretPos+=temp.GetLength();
	m_needScrollToCaret=true;
	NeedUpdate();
	SignalTextChanged(this);
}

void ZTextEdit::SelAll()
{
	m_selBegin=0;
	m_selEnd= m_doc.GetLength();
	Invalidate();
}

void ZTextEdit::SelNone()
{
	m_selBegin=m_caretPos;
	m_selEnd=m_caretPos;
	Invalidate();
}

void ZTextEdit::HomeUp() {
	m_caretPos = 0;
	m_needScrollToCaret = true;
	Invalidate();
}

void ZTextEdit::EndDown()
{
	m_caretPos = m_doc.GetLength();
	m_needScrollToCaret = true;
	Invalidate();
}

void ZTextEdit::NeedUpdate() {
	m_currentWidth = -1;
	ZContainer::NeedUpdate();
}

void ZTextEdit::RemoveSel()
{
	if(m_selBegin!=m_selEnd)
	{
		int selBegin=m_selBegin;
		int selEnd=m_selEnd;
		if(selBegin>selEnd)
		{
			selBegin=m_selEnd;
			selEnd=m_selBegin;
		}

		m_doc.Remove(selBegin,selEnd-selBegin);
		m_selEnd=selBegin;
		m_selBegin=selBegin;
		m_caretPos=selBegin;
	}
}

void ZTextEdit::RemoveEditing()
{
	if(m_editingBegin!=m_editingEnd)
	{
		int selBegin=m_editingBegin;
		int selEnd=m_editingEnd;
		if(selBegin>selEnd)
		{
			selBegin=m_editingEnd;
			selEnd=m_editingBegin;
		}

		m_doc.RemoveEditing(selBegin,m_editingEnd-m_editingBegin);
		m_editingEnd=selBegin;
		m_editingBegin=selBegin;
		m_caretPos=selBegin;
	}
}


void ZTextEdit::SetAttribute(const char* pstrName, const char* pstrValue)
{
	if(stricmp(pstrName, "font") == 0 )
		SetFontName(pstrValue);
	else if(stricmp(pstrName, "textcolor") == 0 )
	{
		SetTextColor(TextToColor(pstrValue));
	}
	else if(stricmp(pstrName, "disabledtextcolor") == 0 )
	{
		SetDisabledTextColor(TextToColor(pstrValue));
	}
	else if(stricmp(pstrName, "textpadding") == 0 )
	{
		RECT rcTextPadding = { 0 };
		ParserRect(&rcTextPadding, pstrValue);
		SetTextPadding(rcTextPadding);
	}
	else if (stricmp(pstrName, "fontsize") == 0)
		SetFontSize(ParserSize(pstrValue));
	else if (stricmp(pstrName, "linepadding") == 0)
	{
		SetLinePadding(atoi(pstrValue));
	}
	else if(stricmp(pstrName, "text") == 0 )
	{
		SetText(pstrValue);
	}
	else if (stricmp(pstrName, "readonly") == 0)
	{
		SetReadOnly(stricmp(pstrValue, "true") == 0);
	}
	else if (stricmp(pstrName, "caretcolor") == 0)
	{
		m_caret->SetColor(TextToColor(pstrValue));
	}
	else if (stricmp(pstrName, "onTextChanged") == 0)
	{
		SetEventAttr("onTextChanged", pstrValue);
		SignalTextChanged.connect((ZLuaWindow*)GetWindow(), &ZLuaWindow::onTextEditChanged);
	}
	else
		ZContainer::SetAttribute(pstrName, pstrValue);
}

void ZTextEdit::PaintText(ZRenderer* render)
{
	RECT rcTemp = { 0 };
	ZFreeTypeFontPtr font=GetFont();
	int lineHeight=font->GetLineHeight() + m_linePadding;

	RECT rc=m_rcItem;
	InsetRect(&rc, &m_rcTextPadding);

	if( m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible()) 
		rc.right -= m_pVerticalScrollBar->GetFixedWidth();

	color_t color=m_dwTextColor;
	if( !IsEnabled() ) {
		color=m_dwDisabledTextColor;
	}

	//绘制文字选中背景
	if(m_selBegin!=m_selEnd)
		PaintTextBk(render);

	//绘制文字
	int iPosY=0;
	if( m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible() ) 
	{
		iPosY = m_pVerticalScrollBar->GetScrollPos();
	}

	int lineBegin=ZMAX(iPosY/lineHeight,0);

	int lineEnd=lineBegin+(rc.bottom-rc.top)/lineHeight+1;
	if (lineEnd>m_rows.size())
		lineEnd=m_rows.size();

	for (int i=0;i<m_rows.size();++i)
	{
		ZTextEditRow& row=m_rows.at(i);
		if (i<lineEnd && i>=lineBegin)
		{
			ZRect rcDst;
			rcDst.x=rc.left;
			rcDst.y=rc.top-iPosY+i*lineHeight + m_linePadding/2;
			rcDst.w=rc.right-rc.left;
			rcDst.h=lineHeight;

			ZWString lineText = m_doc.GetRange(row.m_range.minPos, row.m_range.maxPos);

			render->DrawText(font, lineText.GetString(), m_nFontSize, rcDst, color);
		}
	}


	if (m_editingBegin!=m_editingEnd)
	{
		PaintTextEditing(render);
	}

	//设置光标位置
	if(m_needUpdateCaret)
	{
		RECT rcCaret=GetCaretRect();
		m_caret->SetPos(rcCaret);
		ZRect rc(rcCaret);
		rc.y+=_dpi_scale(CARET_OFFSET_Y);
		if (m_pManager->GetFocus() == this && SDL_IsTextInputActive())
		{
			ZScale scale = GetWindow()->GetRenderScale();
			rc.x = rc.x * scale.den / scale.num;
			rc.y = rc.y * scale.den / scale.num;
			rc.w = rc.w * scale.den / scale.num;
			rc.h = rc.h * scale.den / scale.num;
			SDL_SetTextInputRect(&rc);
		}
		m_needUpdateCaret=false;
	}

	if (m_selBegin == m_selEnd) {
		m_caret->Draw(render);
	}


	if( m_pVerticalScrollBar != NULL && m_pVerticalScrollBar->IsVisible() ) {
		if( IntersectRect(&rcTemp, &m_rcPaint, &m_pVerticalScrollBar->GetPos()) ) {
			m_pVerticalScrollBar->DoPaint(render, rcTemp);
		}
	}
}


void ZTextEdit::LayoutRow(int width)
{
	if (m_currentWidth == width) {
		return;
	}

	ZFreeTypeFontPtr font=GetFont();

	//清空rows
	m_rows.clear();

	int lineWidth=0;
	int lineBegin=0;

	ZWChar lastch = '\n';
	for (int i=0;i<m_doc.GetLength();++i)
	{
		ZWChar ch= m_doc.GetAt(i);
		if (ch=='\n')//换行
		{
			ZTextEditRow row;
			row.m_range.minPos=lineBegin;
			row.m_range.maxPos=i;
			row.m_width=lineWidth;

			lineWidth=0;
			lineBegin=i+1;
			m_rows.push_back(row);
		}
		else
		{
			int w=font->GetWidth(ch);

			//TODO:检测文字换行
			if (lineWidth+w >= width)//宽度超过width，需要换行
			{
				if ((is_line_breakable(lastch,ch, "cn") == LINEBREAK_NOBREAK ||
						is_line_wordbreakable(lastch,ch, "cn") == WORDBREAK_NOBREAK) && i>lineBegin)
				{
					//从lineBegin到i 查找可以换行的字符
					Uint32 curCode = ch;
					size_t breakIdx = i - 1;
					for (; breakIdx>= lineBegin; --breakIdx)
					{
						if (is_line_breakable(m_doc.GetAt(breakIdx), curCode, "cn") != LINEBREAK_NOBREAK ||
								is_line_wordbreakable(m_doc.GetAt(breakIdx), curCode, "cn") != WORDBREAK_NOBREAK)
						{
							++breakIdx;
							break;
						}
						curCode = m_doc.GetAt(breakIdx);
					}

					if (breakIdx <= lineBegin) {
						ZTextEditRow row;
						row.m_range.minPos = lineBegin;
						row.m_range.maxPos = i;
						row.m_width = lineWidth;

						lineWidth = w;
						lineBegin = i;
						m_rows.push_back(row);
					} else {
						//计算当前行的宽度
						int width = 0;
						for (size_t j = lineBegin; j < breakIdx; ++j)
						{
							width += font->GetWidth(m_doc.GetAt(j));
						}

						ZTextEditRow row;
						row.m_range.minPos = lineBegin;
						row.m_range.maxPos = breakIdx;
						row.m_width = width;


						//计算下一行的宽度
						int newwidth = 0;
						for (size_t j = breakIdx; j<=i; ++j)
						{
							newwidth += font->GetWidth(m_doc.GetAt(j));
						}

						lineWidth = newwidth;
						lineBegin = breakIdx;
						m_rows.push_back(row);
					}
				}
				else
				{
					ZTextEditRow row;
					row.m_range.minPos = lineBegin;
					row.m_range.maxPos = i;
					row.m_width = lineWidth;

					lineWidth = w;
					lineBegin = i;
					m_rows.push_back(row);
				}
			}
			else
				lineWidth+=w;
		}

		lastch = ch;
	}

	//添加最后一行
	ZTextEditRow row;
	row.m_range.minPos=lineBegin;
	row.m_range.maxPos= m_doc.GetLength();
	row.m_width=lineWidth;

	m_rows.push_back(row);
	m_needUpdateCaret=true;
	m_currentWidth = width;
}

void ZTextEdit::SetPos(RECT rc)
{
	ZControl::SetPos(rc);
	rc = m_rcItem;
	InsetRect(&rc, &m_rcTextPadding);

	if( m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible() ) 
		rc.right -= m_pVerticalScrollBar->GetFixedWidth();

	LayoutRow(rc.right-rc.left);

	if( m_rows.size() == 0) {
		ProcessScrollBar(rc, 0, 0);
		return;
	}

	ZFreeTypeFontPtr font=GetFont();

	m_needUpdateCaret=true;
	ProcessScrollBar(rc, 0, m_rows.size()* (font->GetLineHeight()+ m_linePadding));

	if (m_needScrollToCaret)
	{
		ScrollToCaret();
	}
}

void ZTextEdit::SetScrollPos(SIZE szPos)
{
	ZContainer::SetScrollPos(szPos);
	m_needUpdateCaret=true;
}

int ZTextEdit::GetLineCount()const
{
	return m_rows.size();
}

int ZTextEdit::LineFromPos(POINT pt)
{
	RECT rc=m_rcItem;
	InsetRect(&rc, &m_rcTextPadding);
	if( m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible()) 
		rc.right -= m_pVerticalScrollBar->GetFixedWidth();

    ZFreeTypeFontPtr font=GetFont();
	int lineHeight=font->GetLineHeight()+ m_linePadding;

	//绘制文字
	int iPosY=pt.y-rc.top;
	if( m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible() ) 
	{
		iPosY += m_pVerticalScrollBar->GetScrollPos();
	}

	int lineBegin=ZMAX(iPosY/lineHeight,0);
	if (lineBegin+1>m_rows.size())
	{
		if(m_rows.size()>0)
			lineBegin=m_rows.size()-1;
		else
			lineBegin=0;
	}
	return lineBegin;
}

POINT ZTextEdit::PosFromLine(int nLine)
{
	POINT pt;
	RECT rc=m_rcItem;
    InsetRect(&rc, &m_rcTextPadding);
	pt.x=rc.left;

    ZFreeTypeFontPtr font=GetFont();
	int lineHeight=font->GetLineHeight() + m_linePadding;

	pt.y=rc.top+nLine*lineHeight;
	if( m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible() ) 
	{
		pt.y -= m_pVerticalScrollBar->GetScrollPos();
	}
	return pt;
}

int ZTextEdit::CharFromPos(POINT pt)
{
	if(m_rows.empty())
		return 0;
	ZFreeTypeFontPtr font=GetFont();

	RECT rc = m_rcItem;
	InsetRect(&rc, &m_rcTextPadding);

	//绘制文字
	int iPosY=pt.y-rc.top;
	if( m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible() ) 
	{
		iPosY += m_pVerticalScrollBar->GetScrollPos();
	}


	int line=LineFromPos(pt);

	ZTextEditRow& row=m_rows[line];
	int offset=pt.x-rc.left;
	int caretPos=rc.left;
	int width=0;
	int caretIdx=0;//光标索引

	for (int i=row.m_range.minPos;i<row.m_range.maxPos;++i)
	{
		ZWChar ch= m_doc.GetAt(i);
		int chWidth=font->GetWidth(ch);

		if (width+chWidth > offset)
		{
			if( offset>(width+chWidth/2))
			{
				++caretIdx;
				caretPos+=chWidth;
			}
			break;
		}
		else
		{
			++caretIdx;
			width+=chWidth;
			caretPos+=chWidth;
		}
	}
	return caretIdx+row.m_range.minPos;
}


POINT ZTextEdit::PosFromChar(int nCh)
{
	RECT rc = m_rcItem;
    InsetRect(&rc, &m_rcTextPadding);

	if (nCh<0)
		nCh=0;

	if (nCh>m_doc.GetLength())
		nCh= m_doc.GetLength();


	int nLine=LineFromChar(nCh);
	ZTextEditRow& row=m_rows[nLine];
	POINT ptLine=PosFromLine(nLine);

    ZFreeTypeFontPtr font=GetFont();

	ZASSERT (nCh<=row.m_range.maxPos);

	int width=0;
	for (int i=row.m_range.minPos;i<nCh;++i)
	{
		ZWChar ch= m_doc.GetAt(i);
		width+=font->GetWidth(ch);
	}

	ptLine.x+=width;
	return ptLine;
}

int ZTextEdit::LineIndex(int nLine) const
{
	if (nLine>=0 && nLine<m_rows.size())
	{
		return m_rows[nLine].m_range.minPos;
	}
	return 0;
}

int ZTextEdit::LineLength(int nLine) const
{
	if (nLine>=0 && nLine<m_rows.size())
	{
		const ZTextEditRow& row=m_rows[nLine];
		return row.m_range.maxPos-row.m_range.minPos;
	}
	return 0;
}

int ZTextEdit::LineFromChar(int nChar)
{
	int nLine=0;
	for (int i=0;i<m_rows.size();++i)
	{
		ZTextEditRow& row=m_rows.at(i);
		if (m_caretPos>=row.m_range.minPos && m_caretPos<=row.m_range.maxPos)
		{
			nLine=i;
			break;
		}
	}
	return nLine;
}

RECT ZTextEdit::GetCaretRect()
{
	POINT pt=PosFromChar(m_caretPos);
    ZFreeTypeFontPtr font=GetFont();
	RECT rcCaret={pt.x,pt.y,pt.x + _dpi_scale(1),pt.y+font->GetLineHeight() +m_linePadding};
	return rcCaret;
}

void ZTextEdit::SetCaretPos(POINT pt)
{
	//计算光标的位置m_caretPos
	if(m_rows.empty())
		return;
	ZFreeTypeFontPtr font=GetFont();

	RECT rc = m_rcItem;
	InsetRect(&rc, &m_rcTextPadding);
	
	if( m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible()) 
		rc.right -= m_pVerticalScrollBar->GetFixedWidth();

	//绘制文字
	int iPosY=pt.y-rc.top;
	if( m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible() ) 
	{
		iPosY += m_pVerticalScrollBar->GetScrollPos();
	}


	int line=LineFromPos(pt);

	ZTextEditRow& row=m_rows[line];
	int offset=pt.x-rc.left;
	int caretPos=rc.left;
	int width=0;
	int caretIdx=0;//光标索引

	for (int i=row.m_range.minPos;i<row.m_range.maxPos;++i)
	{
		ZWChar ch= m_doc.GetAt(i);
		int chWidth=font->GetWidth(ch);

		if (width+chWidth > offset)
		{
			if( offset>(width+chWidth/2))
			{
				++caretIdx;
				caretPos+=chWidth;
			}
			break;
		}
		else
		{
			++caretIdx;
			width+=chWidth;
			caretPos+=chWidth;
		}
	}

	m_caretPos=caretIdx+row.m_range.minPos;
	POINT ptLine=PosFromLine(line);


	RECT rcCaret={caretPos,ptLine.y,caretPos+_dpi_scale(1),0};
	rcCaret.bottom=rcCaret.top+font->GetLineHeight() + m_linePadding;
	m_caret->SetPos(rcCaret);
	m_caret->ShowCaret(true);

	if (!m_readOnly)
	{
		ZRect rc2(rcCaret);
		SDL_StartTextInput();
		rc2.y += _dpi_scale(CARET_OFFSET_Y);
		ZScale scale = GetWindow()->GetRenderScale();
		rc2.x = rc2.x * scale.den / scale.num;
		rc2.y = rc2.y * scale.den / scale.num;
		rc2.w = rc2.w * scale.den / scale.num;
		rc2.h = rc2.h * scale.den / scale.num;
		SDL_SetTextInputRect(&rc2);
	}
}


int ZTextEdit::TextWidth(int nChBegin,int nChEnd)
{
	if (nChEnd<nChBegin)
	{
		int temp=nChBegin;
		nChBegin=nChEnd;
		nChEnd=temp;
	}

	ZFreeTypeFontPtr font=GetFont();
	int width=0;
	for (int i=nChBegin;i<nChEnd;++i)
	{
		ZWChar ch= m_doc.GetAt(i);
		width+=font->GetWidth(ch);
	}
	return width;
}

void ZTextEdit::NeedUpdateCaret()
{
	m_needUpdateCaret=true;
	Invalidate();
}

void ZTextEdit::ScrollToCaret()
{
	//计算滚动位置
	int nLine=LineFromChar(m_caretPos);

	ZFreeTypeFontPtr font=GetFont();
	int lineHeight=font->GetLineHeight()+ m_linePadding;

	RECT rc=m_rcItem;
	
	InsetRect(&rc, &m_rcTextPadding);

	//绘制文字
	int iPosY=0;
	if( m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible() ) 
	{
		iPosY = m_pVerticalScrollBar->GetScrollPos();
	}

	int lineBegin=ZMAX(iPosY/lineHeight,0);

	int lineEnd=lineBegin+(rc.bottom-rc.top)/lineHeight+1;
	if (lineEnd>m_rows.size())
		lineEnd=m_rows.size();

	if (nLine<=lineBegin)
	{
		SIZE sz={0,0};
		if (nLine>0)
		{
			sz.cy=(nLine-1)*lineHeight;
		}
		SetScrollPos(sz);
	}
	else if ((nLine+1)>=lineEnd)
	{
		SIZE sz={0,0};
		if (nLine==m_rows.size()-1)
		{
			sz=GetScrollRange();
		}
		else
		{
			sz.cy=(nLine+1)*lineHeight - (rc.bottom-rc.top);
		}
		SetScrollPos(sz);
	}

	m_needUpdateCaret=true;
	Invalidate();
}


void ZTextEdit::PaintTextBk(ZRenderer* render)
{
	RECT rcTemp = { 0 };
	ZFreeTypeFontPtr font=GetFont();
	int lineHeight=font->GetLineHeight()+ m_linePadding;

	RECT rc=m_rcItem;
	InsetRect(&rc, &m_rcTextPadding);
	if( m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible())
		rc.right -= m_pVerticalScrollBar->GetFixedWidth();


	int selBegin=m_selBegin;
	int selEnd=m_selEnd;
	if(selBegin>selEnd)
	{
		selBegin=m_selEnd;
		selEnd=m_selBegin;
	}

	int iPosY=0;
	if( m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible() ) 
	{
		iPosY = m_pVerticalScrollBar->GetScrollPos();
	}

	int lineBegin=ZMAX(iPosY/lineHeight,0);

	int lineEnd=lineBegin+(rc.bottom-rc.top)/lineHeight+1;
	if (lineEnd>m_rows.size())
		lineEnd=m_rows.size();

	render->SetDrawColor(0xff9bd6ff);
	for (int i=lineBegin;i<lineEnd;++i)
	{
		ZTextEditRow& row=m_rows.at(i);
		ZRect rcDst;
		rcDst.x=rc.left;
		rcDst.y=rc.top-iPosY+i*lineHeight;
		rcDst.w=rc.right-rc.left;
		rcDst.h=lineHeight;


		if (row.m_range.maxPos<=selEnd && row.m_range.minPos>=selBegin)
		{
			//该行被整个选中
			rcDst.w=row.m_width;
			render->FillRect(rcDst);
		}
		else if(selBegin>=row.m_range.minPos && selBegin <=row.m_range.maxPos)
		{
			//右边被选中
			int offset=TextWidth(row.m_range.minPos,selBegin);
			rcDst.x+=offset;
			int width=row.m_width-offset;
			if(selEnd<row.m_range.maxPos)
			{
				width=TextWidth(selBegin,selEnd);
			}
			rcDst.w=width;
			render->FillRect(rcDst);
		}
		else if(selEnd>=row.m_range.minPos && selEnd <=row.m_range.maxPos)
		{
			//左边被选中
			int width=0;
			if(selBegin>row.m_range.minPos)
			{
				width = TextWidth(selBegin, selEnd);
				rcDst.x = width;// TextWidth(selBegin, selEnd);
			}
			else
			{
				width=TextWidth(row.m_range.minPos,selEnd);
			}

			rcDst.w=width;
			render->FillRect(rcDst);
		}

	}

}


void ZTextEdit::PaintTextEditing(ZRenderer* render)
{
	//绘制正在编辑的文字的下划线
	RECT rcTemp = { 0 };
	ZFreeTypeFontPtr font=GetFont();
	int lineHeight=font->GetLineHeight()+ m_linePadding;

	RECT rc=m_rcItem;
	InsetRect(&rc, &m_rcTextPadding);
	if( m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible()) 
		rc.right -= m_pVerticalScrollBar->GetFixedWidth();


	int selBegin=m_editingBegin;
	int selEnd=m_editingEnd;
	if(selBegin>selEnd)
	{
		selBegin=m_editingEnd;
		selEnd=m_editingBegin;
	}

	int iPosY=0;
	if( m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible() ) 
	{
		iPosY = m_pVerticalScrollBar->GetScrollPos();
	}

	int lineBegin=ZMAX(iPosY/lineHeight,0);

	int lineEnd=lineBegin+(rc.bottom-rc.top)/lineHeight+1;
	if (lineEnd>m_rows.size())
		lineEnd=m_rows.size();

	render->SetDrawColor(0xff000000);
	for (int i=lineBegin;i<lineEnd;++i)
	{
		ZTextEditRow& row=m_rows.at(i);
		ZRect rcDst;
		rcDst.x=rc.left;
		rcDst.y=rc.top-iPosY+i*lineHeight;
		rcDst.w=rc.right-rc.left;
		rcDst.h = lineHeight - m_linePadding /2;


		if (row.m_range.maxPos<=selEnd && row.m_range.minPos>=selBegin)
		{
			//该行被整个选中
			rcDst.w=row.m_width;
			render->DrawLine(rcDst.x,rcDst.y+rcDst.h,rcDst.x+rcDst.w,rcDst.y+rcDst.h);
		}
		else if(selBegin>=row.m_range.minPos && selBegin <=row.m_range.maxPos)
		{
			int offset=TextWidth(row.m_range.minPos,selBegin);
			rcDst.x+=offset;
			int width=row.m_width-offset;
			if(selEnd<row.m_range.maxPos)
			{
				width=TextWidth(selBegin,selEnd);
			}
			rcDst.w=width;
			render->DrawLine(rcDst.x,rcDst.y+rcDst.h,rcDst.x+rcDst.w,rcDst.y+rcDst.h);
		}
		else if(selEnd>=row.m_range.minPos && selEnd <=row.m_range.maxPos)
		{
			int width=0;
			if(selBegin>row.m_range.minPos)
			{
				rcDst.x=TextWidth(selBegin,selEnd);
				width=TextWidth(selBegin,selEnd);
			}
			else
			{
				width=TextWidth(row.m_range.minPos,selEnd);
			}

			rcDst.w=width;
			render->DrawLine(rcDst.x,rcDst.y+rcDst.h,rcDst.x+rcDst.w,rcDst.y+rcDst.h);
		}

	}

}



}






